home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / abuse / net / serial.c < prev    next >
C/C++ Source or Header  |  1995-07-23  |  4KB  |  160 lines

  1.  
  2. #include <stdio.h>
  3.  
  4. char *uart_names[]={"none",
  5.             "8250 without scratch register",
  6.             "8250A or 16450",
  7.             "16C1450",
  8.             "16550 with defective FIFO",
  9.             "16550AF/C/CF",
  10.             "16C1550",
  11.             "16552 dual",
  12.             "82510"};
  13.  
  14. enum { UART_NONE,
  15.        UART_8250,
  16.        UART_8250A,
  17.        UART_16C1450,
  18.        UART_16550d,
  19.        UART_16550AF,
  20.        UART_16C1550,
  21.        UART_16552,
  22.        UART_82510 };
  23.        
  24.  
  25.  
  26.  
  27. enum { 
  28.   INTERRUPT_ID_REG=2,
  29.   LINE_CONTROL_REG=3,
  30.   MODEM_CONTROL_REG=4,
  31.   SCRATCH_PAD_REG=7
  32. };
  33.   
  34. void clear_interrupts();
  35. #pragma aux clear_interrupts = "cli";
  36.  
  37. void enable_interrupts();
  38. #pragma aux enable_interrupts = "sti";
  39.  
  40. void out_byte(int port, char value);
  41. #pragma aux out_byte parm [dx] [al] = \
  42.        "out dx, al", \
  43.        "jmp short +2", \
  44.        "jmp short +2";
  45.  
  46.  
  47. char in_byte(int port);
  48. #pragma aux in_byte parm [dx] = \
  49.     "in al, dx",  \
  50.     "jmp short +2", \
  51.     "jmp short +2" \
  52.     modify [al]; 
  53.  
  54.  
  55.  
  56. static void set_divisor_latch_bit1(short port)
  57. {
  58.   out_byte(port,in_byte(port+LINE_CONTROL_REG)&0x80);
  59. }
  60.  
  61. static void set_divisor_latch_bit0(short port)
  62. {
  63.   out_byte(port,in_byte(port+LINE_CONTROL_REG)&0x7f);
  64. }
  65.  
  66.  
  67. // writes a byte to a port and reads it back returns read value
  68. static char io_test(short port, char test_val)
  69. {
  70.   out_byte(port,test_val);
  71.   return in_byte(port);
  72. }
  73.  
  74. static int is_1655x(int port)
  75. {
  76.   set_divisor_latch_bit1(port);
  77.   char bh=io_test(port+INTERRUPT_ID_REG,7);
  78.   out_byte(port+INTERRUPT_ID_REG,0);     // reset register select
  79.   if (bh!=7)
  80.   {
  81.     out_byte(port+MODEM_CONTROL_REG,0x80);     // turn power off
  82.     char al=in_byte(port+MODEM_CONTROL_REG);   // check to see if bit was set
  83.     out_byte(port+MODEM_CONTROL_REG,0);        // turn power back on
  84.     if (al&0x80)
  85.       return UART_16C1550;
  86.     else return UART_16550AF;
  87.   } 
  88.   return UART_16552;
  89. }
  90.  
  91. int detect_uart(short port)
  92. {
  93.   int type;
  94.   clear_interrupts();
  95.   set_divisor_latch_bit1(port);
  96.   if (io_test(port,0x5a)!=0x5a || io_test(port,0xa5)!=0xa5)
  97.     type=UART_NONE;
  98.   {
  99.     enable_interrupts();  
  100.     if (io_test(port+SCRATCH_PAD_REG,0x5a)!=0x5a || 
  101.     io_test(port+SCRATCH_PAD_REG,0xa5)!=0xa5)
  102.       type=UART_8250;
  103.     else
  104.     {
  105.       clear_interrupts();      
  106.       if ((in_byte(port+INTERRUPT_ID_REG)&0xc0)==0xc0)  // FIFO not enabled, try to enable it
  107.         type=is_1655x(port);
  108.       else
  109.       {
  110.     out_byte(port+INTERRUPT_ID_REG,1);    // set to bank 0
  111.     char bh=in_byte(port+INTERRUPT_ID_REG);
  112.     out_byte(port+INTERRUPT_ID_REG,0);    // disable FIFO on 16550
  113.  
  114.     if ((bh&0xc0)==0xc0)                  // 1655x
  115.       type=is_1655x(port);
  116.     else
  117.     {
  118.       if ((bh&0xc0)==0x40)
  119.         type=UART_16550AF;
  120.       else if ((bh&0xc0)==0x80)
  121.         type=UART_16550d;
  122.       else
  123.       {
  124.         out_byte(port+INTERRUPT_ID_REG,0x60);    // set bank 3
  125.         char bh=in_byte(port+INTERRUPT_ID_REG);
  126.         out_byte(port+INTERRUPT_ID_REG,0);       // set bank 0
  127.         if ((bh&0x60)==0x60)
  128.           type=UART_82510;
  129.         else 
  130.         {
  131.           out_byte(port+MODEM_CONTROL_REG,0x80);    // see if power down is available
  132.           char bh=in_byte(port+MODEM_CONTROL_REG);
  133.           out_byte(port+MODEM_CONTROL_REG,0);    // power back on          
  134.           if (bh&0x80)
  135.             type=UART_16C1450;
  136.           else type=UART_8250A;
  137.         }
  138.       }
  139.     }        
  140.       }
  141.     }
  142.   }
  143.  
  144.   enable_interrupts();  
  145.   set_divisor_latch_bit1(port);
  146.   return type;
  147. }
  148.  
  149.  
  150.  
  151. main()
  152. {
  153.   for (int i=0;i<4;i++)
  154.   {
  155.     int port=*((unsigned short *)((0x40<<4)+i*2));
  156.     char *name=(port==0 ? "None" : uart_names[detect_uart(port)]);
  157.     printf("com%d : %x, %s\n",i,port,name);
  158.   }
  159. }
  160.